package com.cencat.common.response;

import com.cencat.common.enums.ErrorCode;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 统一API响应格式
 * 提供标准化的接口返回数据结构
 * 
 * @author cencat
 * @since 2024-01-01
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ApiResponse<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 响应状态码
     */
    private Integer code;

    /**
     * 响应消息
     */
    private String message;

    /**
     * 响应数据
     */
    private T data;

    /**
     * 响应时间戳
     */
    private Long timestamp;

    /**
     * 请求追踪ID
     */
    private String traceId;

    /**
     * 扩展字段
     */
    private Map<String, Object> extra;

    /**
     * 无参构造函数
     */
    public ApiResponse() {
    }

    /**
     * 构造函数
     * 
     * @param code 状态码
     * @param message 消息
     * @param data 数据
     */
    public ApiResponse(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
        this.timestamp = System.currentTimeMillis();
    }

    /**
     * 构造函数
     * 
     * @param errorCode 错误码枚举
     * @param data 数据
     */
    public ApiResponse(ErrorCode errorCode, T data) {
        this.code = errorCode.getCode();
        this.message = errorCode.getMessage();
        this.data = data;
        this.timestamp = System.currentTimeMillis();
    }

    // ==================== 成功响应 ====================

    /**
     * 成功响应（无数据）
     * 
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> success() {
        return new ApiResponse<>(ErrorCode.SUCCESS, null);
    }

    /**
     * 成功响应（带数据）
     * 
     * @param data 响应数据
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<>(ErrorCode.SUCCESS, data);
    }

    /**
     * 成功响应（自定义消息）
     * 
     * @param message 响应消息
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> success(String message) {
        ApiResponse<T> response = new ApiResponse<>(ErrorCode.SUCCESS.getCode(), message, null);
        return response;
    }

    /**
     * 成功响应（自定义消息和数据）
     * 
     * @param message 响应消息
     * @param data 响应数据
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> success(String message, T data) {
        return new ApiResponse<>(ErrorCode.SUCCESS.getCode(), message, data);
    }

    // ==================== 失败响应 ====================

    /**
     * 失败响应（使用错误码枚举）
     * 
     * @param errorCode 错误码枚举
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> error(ErrorCode errorCode) {
        return new ApiResponse<>(errorCode, null);
    }

    /**
     * 失败响应（使用错误码枚举和数据）
     * 
     * @param errorCode 错误码枚举
     * @param data 响应数据
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> error(ErrorCode errorCode, T data) {
        return new ApiResponse<>(errorCode, data);
    }

    /**
     * 失败响应（自定义状态码和消息）
     * 
     * @param code 状态码
     * @param message 错误消息
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> error(Integer code, String message) {
        return new ApiResponse<>(code, message, null);
    }

    /**
     * 失败响应（自定义状态码、消息和数据）
     * 
     * @param code 状态码
     * @param message 错误消息
     * @param data 响应数据
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> error(Integer code, String message, T data) {
        return new ApiResponse<>(code, message, data);
    }

    /**
     * 失败响应（仅消息）
     * 
     * @param message 错误消息
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> error(String message) {
        return new ApiResponse<>(ErrorCode.SYSTEM_ERROR.getCode(), message, null);
    }

    // ==================== 特定场景响应 ====================

    /**
     * 参数错误响应
     * 
     * @param message 错误消息
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> paramError(String message) {
        return new ApiResponse<>(ErrorCode.PARAM_ERROR.getCode(), message, null);
    }

    /**
     * 参数错误响应（带数据）
     * 
     * @param message 错误消息
     * @param data 响应数据
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> paramError(String message, T data) {
        return new ApiResponse<>(ErrorCode.PARAM_ERROR.getCode(), message, data);
    }

    /**
     * 未授权响应
     * 
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> unauthorized() {
        return new ApiResponse<>(ErrorCode.UNAUTHORIZED, null);
    }

    /**
     * 未授权响应（自定义消息）
     * 
     * @param message 错误消息
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> unauthorized(String message) {
        return new ApiResponse<>(ErrorCode.UNAUTHORIZED.getCode(), message, null);
    }

    /**
     * 禁止访问响应
     * 
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> forbidden() {
        return new ApiResponse<>(ErrorCode.FORBIDDEN, null);
    }

    /**
     * 禁止访问响应（自定义消息）
     * 
     * @param message 错误消息
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> forbidden(String message) {
        return new ApiResponse<>(ErrorCode.FORBIDDEN.getCode(), message, null);
    }

    /**
     * 资源不存在响应
     * 
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> notFound() {
        return new ApiResponse<>(ErrorCode.NOT_FOUND, null);
    }

    /**
     * 资源不存在响应（自定义消息）
     * 
     * @param message 错误消息
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> notFound(String message) {
        return new ApiResponse<>(ErrorCode.NOT_FOUND.getCode(), message, null);
    }

    /**
     * 系统错误响应
     * 
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> systemError() {
        return new ApiResponse<>(ErrorCode.SYSTEM_ERROR, null);
    }

    /**
     * 系统错误响应（自定义消息）
     * 
     * @param message 错误消息
     * @param <T> 数据类型
     * @return ApiResponse实例
     */
    public static <T> ApiResponse<T> systemError(String message) {
        return new ApiResponse<>(ErrorCode.SYSTEM_ERROR.getCode(), message, null);
    }

    // ==================== 工具方法 ====================

    /**
     * 判断响应是否成功
     * 
     * @return true-成功，false-失败
     */
    public boolean isSuccess() {
        return ErrorCode.SUCCESS.getCode().equals(this.code);
    }

    /**
     * 判断响应是否失败
     * 
     * @return true-失败，false-成功
     */
    public boolean isError() {
        return !isSuccess();
    }

    /**
     * 设置追踪ID
     * 
     * @param traceId 追踪ID
     * @return 当前实例
     */
    public ApiResponse<T> traceId(String traceId) {
        this.traceId = traceId;
        return this;
    }

    /**
     * 添加扩展信息
     * 
     * @param key 键
     * @param value 值
     * @return 当前实例
     */
    public ApiResponse<T> extra(String key, Object value) {
        if (this.extra == null) {
            this.extra = new HashMap<>();
        }
        this.extra.put(key, value);
        return this;
    }

    /**
     * 批量添加扩展信息
     * 
     * @param extraMap 扩展信息映射
     * @return 当前实例
     */
    public ApiResponse<T> extra(Map<String, Object> extraMap) {
        if (extraMap != null && !extraMap.isEmpty()) {
            if (this.extra == null) {
                this.extra = new HashMap<>();
            }
            this.extra.putAll(extraMap);
        }
        return this;
    }

    /**
     * 获取扩展信息
     * 
     * @param key 键
     * @return 值
     */
    public Object getExtra(String key) {
        return this.extra != null ? this.extra.get(key) : null;
    }

    /**
     * 获取扩展信息（指定类型）
     * 
     * @param key 键
     * @param clazz 值类型
     * @param <E> 值类型泛型
     * @return 值
     */
    @SuppressWarnings("unchecked")
    public <E> E getExtra(String key, Class<E> clazz) {
        Object value = getExtra(key);
        if (value != null && clazz.isInstance(value)) {
            return (E) value;
        }
        return null;
    }

    /**
     * 移除扩展信息
     * 
     * @param key 键
     * @return 当前实例
     */
    public ApiResponse<T> removeExtra(String key) {
        if (this.extra != null) {
            this.extra.remove(key);
        }
        return this;
    }

    /**
     * 清空扩展信息
     * 
     * @return 当前实例
     */
    public ApiResponse<T> clearExtra() {
        if (this.extra != null) {
            this.extra.clear();
        }
        return this;
    }

    /**
     * 转换数据类型
     * 
     * @param newData 新数据
     * @param <R> 新数据类型
     * @return 新的ApiResponse实例
     */
    public <R> ApiResponse<R> convert(R newData) {
        ApiResponse<R> newResponse = new ApiResponse<>(this.code, this.message, newData);
        newResponse.setTimestamp(this.timestamp);
        newResponse.setTraceId(this.traceId);
        newResponse.setExtra(this.extra);
        return newResponse;
    }

    /**
     * 复制响应（不包含数据）
     * 
     * @param <R> 新数据类型
     * @return 新的ApiResponse实例
     */
    public <R> ApiResponse<R> copy() {
        return convert(null);
    }

    /**
     * 获取格式化的时间戳
     * 
     * @return 格式化的时间戳字符串
     */
    public String getFormattedTimestamp() {
        if (this.timestamp == null) {
            return null;
        }
        return LocalDateTime.ofInstant(
            java.time.Instant.ofEpochMilli(this.timestamp),
            java.time.ZoneId.systemDefault()
        ).format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * 获取响应摘要信息
     * 
     * @return 摘要信息字符串
     */
    public String getSummary() {
        return String.format("ApiResponse{code=%d, message='%s', hasData=%s, timestamp=%s}",
            this.code, this.message, this.data != null, getFormattedTimestamp());
    }

    // Getter and Setter methods
    public Integer getCode() {
        return code;
    }
    
    public void setCode(Integer code) {
        this.code = code;
    }
    
    public String getMessage() {
        return message;
    }
    
    public void setMessage(String message) {
        this.message = message;
    }
    
    public T getData() {
        return data;
    }
    
    public void setData(T data) {
        this.data = data;
    }
    
    public Long getTimestamp() {
        return timestamp;
    }
    
    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }
    
    public String getTraceId() {
        return traceId;
    }
    
    public void setTraceId(String traceId) {
        this.traceId = traceId;
    }
    
    public Map<String, Object> getExtra() {
        return extra;
    }
    
    public void setExtra(Map<String, Object> extra) {
        this.extra = extra;
    }

    @Override
    public String toString() {
        return getSummary();
    }
}